package com.jsu.service.impl;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.internal.util.StringUtils;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.jsu.client.ActivityClient;
import com.jsu.config.MessageProducer;
import com.jsu.config.RedisCache;
import org.example.model.activity.pojo.Activity;
import org.example.model.common.enums.WebHttpCodeEnum;
import org.example.model.pay.dto.PaymentDTO;
import org.example.model.pay.enums.PayStatus;
import com.jsu.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import com.jsu.mapper.PaymentMapper;
import org.example.model.pay.pojo.AliPay;
import org.example.model.pay.pojo.Payment;
import org.example.model.common.dtos.ResponseResult;
import org.example.utils.common.ALiYunCodeUtil;
import org.example.utils.common.IdsUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class PaymentServiceImpl implements PaymentService {


    @Value("${alipay.notifyUrl}")
    private String notifyUrl;
    @Value("${alipay.alipayPublicKey}")
    private String publicKey;

    @Autowired
    private MessageProducer messageProducer;//声明生产者

    @Autowired
    private AlipayClient alipayClient;


    @Autowired
    private PaymentMapper paymentMapper;

    @Autowired(required = false)
    private IdsUtils idsUtils;

    @Autowired(required = false)
    private ALiYunCodeUtil aLiYunCodeUtil;
    @Autowired
    private RedisCache redisCache;

    @Autowired(required = false)
    private ActivityClient activityClient;

    /**
     *
     * @param payment 支付订单对象，创建成功以后发送延时队列，订单倒计时则自动取消订单
     * @return
     */
    @Override
    public ResponseResult createPayment(Payment payment) {
        if (Objects.isNull(payment)){
            throw new RuntimeException("订单为空，创建失败");
        }
        String uuid = UUID.randomUUID().toString();
        int pkId = Math.abs(uuid.replaceAll("[^\\d]", "").hashCode());
        payment.setPkId(pkId);
        Date date = new Date();
        payment.setCreateTime(date);//设置创建时间
        payment.setStatus(PayStatus.WAIT_BUYER_PAY.getValue());//设置成创建订单未支付状态
        //设置15分钟倒计时
        redisCache.setCacheObject("payment:info:"+payment.getPkId(), JSON.toJSONString(payment), 15, TimeUnit.MINUTES);
        //返回支付订单主键id
        return ResponseResult.okResult(payment.getPkId());
    }

    @Override
    public void pay(AliPay aliPay, HttpServletResponse response) throws IOException {
        //从缓存里面拿到订单数据，没有则返回订单超时
        String paymentInfo = redisCache.getCacheObject("payment:info:"+aliPay.getPaymentId());
        if (Objects.isNull(paymentInfo)){
            response.setStatus(400);
            response.setHeader("Content-Type", "text/plain;charset=UTF-8");
            response.getWriter().write("支付失败，订单超时");
            response.getWriter().flush();
            return;
        }


        // 准备支付的参数，包括需要支付的订单的id，价格，物品名称，
        AlipayTradePagePayModel model = new AlipayTradePagePayModel();
        model.setOutTradeNo(String.valueOf(aliPay.getPaymentId())); // 需要支付的订单id，自定义的订单id，不能重复，唯一，已经支付的无法继续支付
        model.setTotalAmount(aliPay.getPrice()); // 需要支付的钱 model.setTotalAmount("88.88");
        model.setSubject(aliPay.getSubject()); // 要支付的物品，比如 model.setSubject("Iphone6 16G");
        model.setProductCode("FAST_INSTANT_TRADE_PAY");
        // 5.创建支付的请求，把上面的准备支付的参数进行set
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        request.setBizModel(model);
        //设置支付宝异步回调
        request.setNotifyUrl(notifyUrl);
        /**
         * 设置支付宝支付成功返回的页面
         * 这里让支付成功直接回到static下的一个静态页面中
         */
        //request.setReturnUrl("http://localhost:8091/aliPayReturn.html");

        // 调用ali客户端alipayClient，用客户端执行请求，获取响应，获取.getBody()，拿到form表单
        // 执行请求，拿到响应的结果，返回给浏览器
        String form = "";
        try {
            form = alipayClient.pageExecute(request).getBody(); // 调用SDK生成表单
            log.debug(">>>>>>getAliPayFrom");
            System.out.println("getAliPayFrom");
            System.out.println(form);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }

        // 表单数据作为响应返回给前端，显示前端页面
        response.setContentType("text/html;charset=UTF-8"); // 设置头部
        response.getWriter().write(form);// 直接将完整的表单html输出到页面
        response.getWriter().flush();

    }

    @Override
    public ResponseResult payNotify(HttpServletRequest request) throws AlipayApiException {
        log.debug(">>>>>>>支付宝异步回调");
        Map<String, String[]> parameterMap = request.getParameterMap();
        Set<String> keySet = parameterMap.keySet(); // 获取http请求里面的所有键

        /**
         * paramsMap如下：
         * {gmt_create=2023-07-31 15:54:11, charset=UTF8,
         * gmt_payment=2023-07-31 15:54:26,
         * notify_time=2023-07-31 15:54:27,
         * sign=fsCABNzc5hax4mwwMULluDiEAT70Kqj77uTMcCgSi82AU6tP5LGbXucEvP7CbvjXrYo5g3hrz5xRQAwddE7qU9Qyrg0v3EnearJBcW4It6N+VNBQ7yfY/W79eKRSKspLBKHRa21RILjyRrmQYG4Cw8R7twP7y0lDCOE8j3rV6ZyGfhiQ7EXp49d6HpgcIT1NjgJjQYSyJFdgyqkzFljKRfbhwPFAtubsmd8IcJCU7XI3YosSKnDhQaCA6ec4dmQiWtvcTbOLNR/r2Sou7rCnI7s1lc8pKeEsuacWTZW2FVR7hdHoLZ/expaRQIt+dNzA86lwQxu3SRCQ9wNTPICv1A==,
         * buyer_id=2088722005286475, invoice_amount=12.56, version=1.0, notify_id=2023073101222155427086470500776505,
         * fund_bill_list=[{"amount":"12.56","fundChannel":"ALIPAYACCOUNT"}],
         * notify_type=trade_status_sync,
         * subject=iPhone, // 物品名称
         * out_trade_no=202307311553, // 进行支付的订单id，唯一，商家自定义，即支付时传入的 String orderId
         * total_amount=12.56, // 总价格
         * trade_status=TRADE_SUCCESS, // 支付状态
         * trade_no=2023073122001486470500697216, auth_app_id=9021000123613164,
         * receipt_amount=12.56, point_amount=0.00,
         * buyer_pay_amount=12.56, app_id=9021000123613164, sign_type=RSA2, seller_id=2088721005318559}
         */
        Map<String,String> paramsMap = new HashMap<>(); // 专门用来放置请求里面的参数
        for(String key : keySet){
            paramsMap.put(key, request.getParameter(key));
        }
        System.out.println("*************");
        System.out.println(paramsMap);

        // 验证签名
        String sign = paramsMap.get("sign");
        String contentV1 = AlipaySignature.getSignCheckContentV1(paramsMap);
        boolean rsa256CheckSignature = AlipaySignature.rsa256CheckContent(contentV1, sign, publicKey, "UTF-8");
        if (rsa256CheckSignature && "TRADE_SUCCESS".equals(paramsMap.get("trade_status"))){
            // 签名验证成功 并且 支付宝回调的状态是成功状态 TRADE_SUCCESS
            log.info("在{}，买家{}进行订单{}的付款，交易名称{}，付款金额{}",
                    paramsMap.get("gmt_payment"),paramsMap.get("buyer_id"),paramsMap.get("out_trade_no"),paramsMap.get("subject"),paramsMap.get("total_amount"));

            // 支付成功，修改数据库中该订单的状态.发送短信通知用户
            /*String phone = idsUtils.getUserID();
            try {
                aLiYunCodeUtil.sendPayMail(phone,paramsMap.get("total_amount"),paramsMap.get("buyer_id"));
            } catch (ExecutionException e) {
                throw new RuntimeException(e);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }*/

            // 比如：流程，根据订单ID查询出一条数据，修改该条订单的数据，或者只有支付成功，才给数据库里面新增一条数据
            String paymentId = paramsMap.get("out_trade_no");
            String trade_no = paramsMap.get("trade_no");
            log.info("支付成功，订单号：{}，支付宝交易号：{}",paymentId,trade_no);
            //更新支付表状态
            update(paymentId,trade_no);
        }
        return ResponseResult.okResult("支付异步回调信息");
    }

    @Override
    public void toRefund(HttpServletResponse response, Integer paymentId,Float amount) throws IOException {

        ModelAndView mv=new ModelAndView();
        // 设置编码格式
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        //设置请求参数
        AlipayTradeRefundRequest alipayRequest = new AlipayTradeRefundRequest();
        //商户订单号，必填
        String out_trade_no = String.valueOf(paymentId);
        //需要退款的金额，该金额不能大于订单金额，必填
        String refund_amount = String.valueOf(amount);
        // 字符转义很重要
        alipayRequest.setBizContent("{\"out_trade_no\":\"" + out_trade_no + "\","
                + "\"refund_amount\":\"" + refund_amount + "\"}");
        //请求
        AlipayTradeRefundResponse result = null;
        try {
            result = alipayClient.execute(alipayRequest);
            Payment payment = paymentMapper.selectById(paymentId);
            if (Objects.isNull(payment)){
                throw new RuntimeException("订单不存在");
            }
            else{
                //更新订单状态为退款成功
                payment.setStatus(PayStatus.REFUNDING.getValue());
                payment.setUpdateTime(new Date());
                paymentMapper.updateById(payment);

            }
            //输出
            log.info(String.valueOf(result));
            if (result.isSuccess()) {

                System.out.println("退款成功");
                response.setStatus(200);
                response.setHeader("Content-Type", "text/plain;charset=UTF-8");
                response.getWriter().write("success");
                return;
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        response.setStatus(400);
        response.setHeader("Content-Type", "text/plain;charset=UTF-8");
        response.getWriter().write("fail");
        return;
    }

    /**
     * 用户中心-订单列表
     * @param userId
     * @return
     */
    @Override
    public ResponseResult paymentList(Integer userId) {
        List<Payment> paymentList = paymentMapper.selectByUserId(userId);
        List<PaymentDTO> paymentDTOList = new ArrayList<>();
        if(!paymentList.isEmpty()){
            for (Payment payment : paymentList) {
                Activity activity = (Activity) activityClient.getRegistrationByActivityId(payment.getActivityId()).getData();
                PaymentDTO paymentDTO = new PaymentDTO();
                BeanUtils.copyProperties(payment,paymentDTO);//赋值
                paymentDTO.setStartTime(activity.getActivityStarttime());
                paymentDTO.setEndTime(activity.getActivityEndtime());
                paymentDTO.setStatusName(getTypeInChinese(activity.getType()));
                paymentDTOList.add(paymentDTO);
            }
            return ResponseResult.okResult(paymentDTOList);
        }

        return ResponseResult.errorResult(WebHttpCodeEnum.DATA_NOT_EXIST);
    }

    public String getTypeInChinese(Integer type) {
        switch (type) {
            case 1:
                return PayStatus.WAIT_BUYER_PAY.getDesc();
            case 2:
                return PayStatus.TRADE_SUCCESS.getDesc();
            case 3:
                return PayStatus.TRADE_CLOSED.getDesc();
            case 4:
                return PayStatus.REFUNDING.getDesc();
            default:
                return "未知类型"; // 如果传入的类型数字不在范围内，返回未知类型
        }
    }

    /**
     * 付款后更新订单表数据信息
     * @param alipayTradeNo 支付宝交易凭证号
     */
    @Override
    public ResponseResult update(String tradeNo, String alipayTradeNo) {
        String cacheObject = redisCache.getCacheObject("payment:info:" + tradeNo);
        log.info(cacheObject);
        if (!StringUtils.isEmpty(cacheObject)){
            Payment payment = JSON.parseObject(cacheObject, Payment.class);
            payment.setPkId(Integer.valueOf(tradeNo));
            payment.setStatus(PayStatus.TRADE_SUCCESS.getValue());//设置完成支付状态
            Date date = new Date();
            payment.setUpdateTime(date);
            payment.setAlipayId(alipayTradeNo);
            log.info("更新订单表数据信息：{}",payment);
            paymentMapper.insert(payment);
            redisCache.deleteObject("payment:info:" + tradeNo);
        }

        return ResponseResult.okResult("支付成功");
    }

}
